The SOLID principles are commonly recognized as best practices when working with object oriented code. If you understand and adhere to these principles, the structure of the code you create will be very robust, loosly coupled and easy to understand for other programmers.

The SOLID acronym stands for:

  • Single Responsibility Principle (SRP)
  • Open/Closed princicple
  • Liskov substitution principle
  • Interface segregation principle
  • Dependency Inversion princpiple

Single Responsiblity Principle

luis-villasmil-mlVbMbxfWI4-unsplash.jpg

First up is the Single Responsibility Principle. It was originally coined by Robert Martin (aka. Uncle Bob) and according to Wikipedia it is defined as “...states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class, module or function. All its services should be narrowly aligned with that responsibility.”

Often your hear people use the quote from Uncle Bob below to describe SRP:

“A class should have only one reason to change” - Robert Martin

However this definition often creates more confusion than understanding, since the definition of “reason to change” may vary from one person to another. To clear up some of the confusion he wrote a blog post, explaining more in depth what he means when he says “A class should have only one reason to change”. In the blog post he explains that in order to better understand what “a reason to change” is, it can help to think about SRP as a principle that applies to people. A class or a module in the code, should only recieve requests for changes from one specific person (or “a single tightly coupled group of people representing a single narrowly defined business function”). The idea is that a class should not contain code that contains requirements coming from more than one “person“. I prefer to think of it as ”business unit“ instead of a person.

Let’s try to quantify this with an example. Image that you have a class that looks like this:

public class Employee{
    public string PrintEmployeeData(){...}
    public decimal CalculatePay(Date fromDate to){...}
}


The PrintEmployeeData method is used by the HR department, to get an overview over the employees address, phone number and other personal data.

The CalculatePay method is used by the finance department to calculate how much the employee should be paid, for the work done in a given time frame.

The logic in the two methods contains requirements that come from two separate business units (ie. the HR department and the finance department). The HR department should not be able to make requests for changes in the CalculatePay method and the same applies for the finance department to the PrintEmployeeData. To implement the above with SRP in mind, it would make sense to have a class that handles the logic concerning printing employee data and another class that handles the pay calculation.

SRP mainly addresses the responsiblities of a class, but I like to apply the same priciple to methods as well. The CalculatePay method might consist of multiple calculations (ie. hours worked, commision, bonus). Calculating each of these should have it’s own method and possibly it’s own class. This makes the code much easier to read and understand, since the number of lines in each method will be much smaller.

public class PayCalculator{
    public decimal CalculatePay(Date fromDate to){
        var hoursPay = CalculateHoursPay(fromto);
        var commision = CalculateCommision(fromto);
        var bonus = CalculateBonus(fromto);
        var total = hoursPay + commision + bonus;
        return total;
    }
    private decimal CalculateHoursPay(Date fromDate to){
         /*Hours logic here*/ 
    }
    private decimal CalculateCommision(Date fromDate to){ 
        /*Commision logic here*/ 
    }
    private decimal CalculateBonus(Date fromDate to){ 
        /*Bonus logic here*/ 
    }
}


To sum up: make sure that when you design and write your code, to ask yourself which business unit could have requirements for this code snippet. If the answer is more than one business unit, consider that as a code smell and look into if you could organize your code differently. Also try to look at each method you write and try to see if the methods does more than one thing. A code smell in this regard is if the code has sections of code divided by an empty line. This could indicate that the method is doing more than one thing. Consider to move each section of the code into it’s own method (like demonstrated in the code above).

Comments

Be the first to post a comment

Post a comment